/*
 * handle_sprite.cpp
 *
 *  Created on: Nov 8, 2013
 *      Author: killerg
 */

#include "../../server_deps.h"
#include "../../server.h"
#include "../../client_session.h"
#include "../player_data.h"
#include "../proto_mgr.h"
#include "../chat_mgr.h"
#include "../game_cfg.h"

#include "share/util.h"

// 探索
void handle_cspriteexplore(client_session_t* sess, cs::CMsg* msg) {
    auto player = sess->player;
    if (NULL == player)
        return;

    auto explore = msg->spriteexplore();

    int32_t cur_star = player->att(Pl4s_SpriteStarCur);
    if (cur_star < 0 || cur_star >= StarProtoNum)
        return;

    const tagProtoStar* star_proto = ARProto(Star, cur_star);
    if (NULL == star_proto) {
        sess->send_notify("无效星星");
        return;
    }

    int32_t consumeid = -1;
    if (explore.has_money()) {
        consumeid = star_proto->money_consumeid;
        if (player->att(Pl4s_SpriteExplNumMoney) <= 0) {
            sess->send_notify("人民币消耗次数最大");
            return;
        }
    } else
        consumeid = star_proto->gamemoney_consumeid;

    if (!player->can_consume(consumeid)) {
        sess->send_notify("消耗不足");
        return;
    }

    int32_t index = random(star_proto->next_star_prob, star_proto->next_star_num);
    if (index < 0) {
        sess->send_notify("无效索引");
        return;
    }

    int32_t protoid = star_proto->next_star_proto[index];
    if (protoid < 0 || protoid >= StarProtoNum) {
        sess->send_notify("无效next星星");
        return;
    }

    auto slot = EPlAtt4Save(Pl4s_SpriteStarBegin + protoid);

    int32_t star_num = player->att(slot);
    ++star_num;
    if (explore.has_money()) {
    	if (prob(3000))
    		++star_num;
    } else {
    	if (prob(1000))
    		++star_num;
    }
    player->att(slot, star_num);
    player->att(Pl4s_SpriteStarCur, protoid);

    player->consume(consumeid);
    if (star_proto->money_consumeid == consumeid)
        player->att(Pl4s_SpriteExplNumMoney, player->att(Pl4s_SpriteExplNumMoney)-1);

    sess->stat.add_consume_byid(ECT_SpriteStarWalk, -1, consumeid);
    player->att(Pl4s_CntSpriteExplore, player->att(Pl4s_CntSpriteExplore) + 1);
}

// 召唤
void handle_cspritesummon(client_session_t* sess, cs::CMsg* msg) {
    auto player = sess->player;
    if (NULL == player)
        return;

    if (player->sprites.size() >= PlayerMaxSpriteNum) {
        sess->send_notify("达到最大妖精数量");
        return;
    }

    auto summon = msg->spritesummon();
    int32_t type = summon.type();
    if (!ESpriteQuality_IsValid(type)) {
        sess->send_notify("无效精灵资质类型");
        return;
    }

    const tagProtoSpriteQuality* quality_proto = ARProto(SpriteQuality, type);
    if (NULL == quality_proto) {
        sess->send_notify("无效精灵资质原型");
        return;
    }

    int32_t stars_num[StarProtoNum] = {0};
    for (int i=0; i<StarProtoNum; ++i)
        stars_num[i] = player->att(EPlAtt4Save(Pl4s_SpriteStarBegin + i));

    for (int i=0; i<StarProtoNum; ++i) {
        if (stars_num[i] < quality_proto->consume_star[i]) {
            sess->send_notify("星星不够");
            return;
        }
    }

    if (quality_proto->sprite_protos.size() == 0) {
        sess->send_notify("没有候选精灵");
        return;
    }
    int32_t sprite_protoid = quality_proto->sprite_protos[random()%quality_proto->sprite_protos.size()];
    if (sprite_protoid < 0) {
        sess->send_notify("无效精灵");
        return;
    }

    for (int i=0; i<StarProtoNum; ++i) {
        auto slot = EPlAtt4Save(Pl4s_SpriteStarBegin+i);
        player->att(slot, stars_num[i] - quality_proto->consume_star[i]);
    }

    sprite_t* sprite = new sprite_t;
    if (!sprite->init(sprite_protoid, player->n.valid_sprite_serial++) || !player->add_sprite(sprite, false)) {
        --player->n.valid_sprite_serial;
        sprite->destroy();
        safe_del(sprite);

        sess->send_notify("精灵初始化失败");
        return;
    }

    if (type >= g_game_cfg->BroadSpriteQuality)
        g_chat->broad_scroll(fmt_cstr("5,%s,%d", player->att(Plss_Name).c_str(), sprite->proto->id));

    player->att(Pl4s_CntSpriteSummon, player->att(Pl4s_CntSpriteSummon) + 1);
}

// 分解
void handle_cspritedecompose(client_session_t* sess, cs::CMsg* msg) {
    auto player = sess->player;
    if (NULL == player)
        return;

    auto decompose = msg->spritedecompose();
    int protoid = decompose.star_pos();
    int num = decompose.star_num();
    auto slot = EPlAtt4Save(protoid + Pl4s_SpriteStarBegin);

    if (protoid < 0 || protoid >= StarProtoNum) {
        sess->send_notify("无效位置");
        return;
    }
    if (num <= 0 || num > MaxStarNum) {
        sess->send_notify("无效数量");
        return;
    }

    int has_num = player->att(slot);
    if (has_num < num) {
        sess->send_notify("数量不够");
        return;
    }

    const tagProtoStar* star_proto = ARProto(Star, protoid);
    if (NULL == star_proto) {
        sess->send_notify("无效星星");
        return;
    }

    int32_t anima = player->att(Pl4s_SpriteAnima);
    player->att(Pl4s_SpriteAnima, anima + star_proto->anima_gain);

    player->att(slot, has_num-num);
}

// 技能升级
void handle_cspriteskilllevelup(client_session_t* sess, cs::CMsg* msg) {
    auto player = sess->player;
    if (NULL == player)
        return;

    auto skilllevelup = msg->spriteskilllevelup();
    auto sprite = player->sprites.get(skilllevelup.serial());
    if (NULL == sprite) {
        sess->send_notify("无此精灵");
        return;
    }

    int pos = skilllevelup.skill_pos();
    if (pos < 0 || pos > SpriteSkillNum) {
        sess->send_notify("位置错误");
        return;
    }

    int level = sprite->skill_level[pos];
    if (level >= sprite->proto->max_skill_level) {
        sess->send_notify("达到技能等级限制");
        return;
    }

    const tagProtoSpriteSkillLevel* level_proto = ARProto(SpriteSkillLevel, level);
    if (NULL == level_proto) {
        sess->send_notify("无效等级");
        return;
    }
    const tagProtoSpriteSkillLevel* next_level_proto = ARProto(SpriteSkillLevel, level+1);
    if (NULL == next_level_proto) {
        sess->send_notify("无效下一等级");
        return;
    }

    int anima_need = level_proto->anima_consume[sprite->proto->quality];
    int anima = player->att(Pl4s_SpriteAnima);
    if (anima < anima_need) {
        sess->send_notify("灵气不足");
        return;
    }

    anima -= anima_need;
    ++sprite->skill_level[pos];
    player->sprite_chg.insert(sprite->serial);
    player->att(Pl4s_SpriteAnima, anima);
    sprite->calc_combat_force();
    if (sprite->serial == player->cur_sprite)
    	player->need_calc_total_cf = true;
}

// 释放
void handle_cspriterelease(client_session_t* sess, cs::CMsg* msg) {
    auto player = sess->player;
    if (NULL == player)
        return;

    auto release = msg->spriterelease();
    auto sprite = player->sprites.get(release.serial());
    if (NULL == sprite) {
        sess->send_notify("无此精灵");
        return;
    }

    const tagProtoSpriteQuality* quality_proto = ARProto(SpriteQuality, sprite->proto->quality);
    if (NULL == quality_proto) {
        sess->send_notify("无效品质");
        return;
    }

    int gain_anima = player->att(Pl4s_SpriteAnima);
    for (int i=0; i<SpriteSkillNum; ++i) {
        int32_t level = sprite->skill_level[i];
        gain_anima += (quality_proto->factor1 + (level - 1) * quality_proto->factor2 * level / 2.0) * 0.7f;
    }

    sprite = player->remove_sprite(sprite->serial);
    if (NULL == sprite) {
        sess->send_notify("无法移除");
        return;
    }

    sprite->destroy();
    safe_del(sprite);

    player->att(Pl4s_SpriteAnima, gain_anima);
    player->sprite_remove.insert(release.serial());
}

// 休息出战
void handle_cspriterest(client_session_t* sess, cs::CMsg* msg) {
    auto player = sess->player;
    if (NULL == player)
        return;

    auto rest = msg->spriterest();

    if (rest.rest()) {
        player->att(Pl4s_CurSprite, -1);
    } else if (rest.has_serial()) {
        auto sprite = player->sprites.get(rest.serial());
        if (NULL == sprite) {
            sess->send_notify("无此精灵");
            return;
        }
        player->att(Pl4s_CurSprite, rest.serial());
    }

    player->need_calc_total_cf = true;
}
